﻿using System.ComponentModel;
using System.Reflection;

using BodaNetCommunications.CommBase.Interfaces;
using BodaNetCommunications.Utilities.DataLibs;
using BodaNetCommunications.Utilities.Results;
using BodaNetCommunications.Utilities.Tools;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace BodaNetCommunications.ModbusTcpComs
{
    public class ModbusTcpNetWork : IBodaNetWork
    {
        private BodaModbusTcpClient _bodaNodeModbusTcp = new BodaModbusTcpClient();

        private SoftIncrementCount softIncrementCount;              // 自增消息的对象
        /// <summary>
        /// 获取modbus协议自增的消息号，你可以自定义消息的细节。
        /// </summary>
        public SoftIncrementCount MessageId
        {
            get { return softIncrementCount; }
        }

        /// <summary>
        /// 额外的读写或者初始化参数
        /// </summary>
        public JObject ExtraParams { get; private set; }

        public ModbusTcpNetWork()
        {
            softIncrementCount = new SoftIncrementCount(ushort.MaxValue);
        }

        /// <summary>
        /// Modbus连接
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        /// <param name="extraInfos">第一次赋值后，后续可以不用继续传递该参数</param>
        /// <returns></returns>
        public BodaResult<bool> Connect(string ip, string port, JObject extraInfos)
        {
            if (extraInfos != null)
            {
                ExtraParams = extraInfos;
            }

            var resConnect = _bodaNodeModbusTcp.Connect(ip, port);
            if (resConnect.IsSuccess)
            {
                ExtraInitAction(extraInfos);
            }
            return resConnect;
        }

        public void ExtraInitAction(JObject jObject = null)
        {
            JObject keyValues = jObject ?? ExtraParams;
            if (keyValues == null) return;
            if (_bodaNodeModbusTcp == null) return;
            // 反射获取所有的JsonProperty属性
            var modbusType = _bodaNodeModbusTcp.GetType();
            var jsonProperties = modbusType.GetProperties().Where(m => m.IsDefined(typeof(JsonPropertyAttribute), false))?.ToList();
            if (jsonProperties == null || jsonProperties.Count == 0) return;
            foreach (var item in jsonProperties)
            {
                var proType = item.PropertyType;
                var defaultVal = item.GetCustomAttribute<DefaultValueAttribute>();
                // 获取 MyIntProperty 属性的默认值
                object intDefaultValue = defaultVal == null ? Activator.CreateInstance(proType) : defaultVal.Value;
                // 设置modbus读写数据的参数
                var obj = BodaBasicTool.GetValueFromJsonObject(keyValues, item.Name, intDefaultValue) ?? defaultVal;

                // 获取属性的数据类型
                var val = Convert.ChangeType(obj, proType);
                item.SetValue(_bodaNodeModbusTcp, val);
            }
        }

        public void DisConnect()
        {
            _bodaNodeModbusTcp?.DisConnect();
        }

        public void Dispose()
        {
            DisConnect();
        }

        public bool Isconnected()
        {
            return _bodaNodeModbusTcp.IsConnected;
        }

        public BodaResult<byte[]> Read(string address, ushort length)
        {
            // 获取功能码和读取地址
            BodaResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, _bodaNodeModbusTcp.AddressStartWithZero, ModbusFunctionCode.UnknowFunction);
            if (!analysis.IsSuccess) return BodaResult.CreateFailedResult<byte[]>(analysis);

            List<byte> lists = new List<byte>();
            ushort alreadyFinished = 0;
            while (alreadyFinished < length)
            {
                // 如果数量超过120的，则会分多次去读取数据
                ushort lengthTmp = (ushort)Math.Min((length - alreadyFinished), 120);
                BodaResult<byte[]> read = ReadModBusBase(analysis.Content.AddressAdd(alreadyFinished), lengthTmp);
                if (!read.IsSuccess) return BodaResult.CreateFailedResult<byte[]>(read);

                lists.AddRange(read.Content);
                alreadyFinished += lengthTmp;
            }
            return BodaResult.CreateSuccessResult(lists.ToArray());
        }

        /// <summary>
        /// 读取服务器的数据，需要指定不同的功能码
        /// </summary>
        /// <param name="address">地址</param>
        /// <param name="length">长度</param>
        /// <returns>带是否成功的结果数据</returns>
        private BodaResult<byte[]> ReadModBusBase(ModbusAddress address, ushort length)
        {
            BodaResult<byte[]> resultBytes = new BodaResult<byte[]>();
            switch (address.Function)
            {
                case ModbusFunctionCode.ReadCoil:
                    {
                        resultBytes = _bodaNodeModbusTcp.ReadOutputStatus(address.Address, length);
                    }
                    break;

                case ModbusFunctionCode.ReadDiscrete:
                    {
                        resultBytes = _bodaNodeModbusTcp.ReadInputStatus(address.Address, length);
                    }
                    break;

                case ModbusFunctionCode.ReadRegister:
                    {
                        resultBytes = _bodaNodeModbusTcp.ReadKeepReg(address.Address, length);
                    }
                    break;

                case ModbusFunctionCode.ReadInputRegister:
                    {
                        resultBytes = _bodaNodeModbusTcp.ReadInputReg(address.Address, length);
                    }
                    break;

                default:
                    resultBytes = BodaResult.CreateFailedResult<byte[]>(BodaResult.CreateFailedResult($"功能码【{address.Function}】无效"));
                    break;
            }

            //BodaResult<byte[]> command = BuildReadRegisterCommand(address, length);
            //if (!command.IsSuccess) return BodaResult.CreateFailedResult<byte[]>(command);

            //BodaResult<byte[]> resultBytes = CheckModbusTcpResponse(command.Content);
            //if (resultBytes.IsSuccess)
            //{
            //    // 二次数据处理
            //    if (resultBytes.Content?.Length >= 9)
            //    {
            //        byte[] buffer = new byte[resultBytes.Content.Length - 9];
            //        Array.Copy(resultBytes.Content, 9, buffer, 0, buffer.Length);
            //        resultBytes.Content = buffer;
            //    }
            //}
            return resultBytes;
        }

        public BodaResult<bool> ReadBool(string address)
        {
            var rsp = Read(address, 1);
            if (rsp.IsSuccess == false) return BodaResult.CreateFailedResult<bool>(rsp.Message);
            //ModbusAddress.VerifyModbusAddress(address, true, out var start, out _);
            var result = BitLib.GetBitArrayFromByteArray(rsp.Content, false)[0];
            BodaResult<bool> bodaResult = BodaResult<bool>.CreateSuccessResult(result);
            return bodaResult;
        }

        public BodaResult<bool[]> ReadBool(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<T> ReadCustomer<T>(string address) where T : IDataTransfer, new()
        {
            throw new NotImplementedException();
        }

        public BodaResult<double> ReadDouble(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<double[]> ReadDouble(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<float> ReadFloat(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<float[]> ReadFloat(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<short> ReadInt16(string address)
        {
            var rsp = Read(address, 1);
            if (rsp.IsSuccess == false) return BodaResult.CreateFailedResult<short>(rsp.Message);
            //ModbusAddress.VerifyModbusAddress(address, true, out var start, out _);
            var result = ShortLib.GetShortArrayFromByteArray(rsp.Content)[0];
            BodaResult<short> bodaResult = BodaResult<short>.CreateSuccessResult(result);
            return bodaResult;
        }

        public BodaResult<short[]> ReadInt16(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<int> ReadInt32(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<int[]> ReadInt32(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<long> ReadInt64(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<long[]> ReadInt64(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<string> ReadString(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<ushort> ReadUInt16(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<ushort[]> ReadUInt16(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<uint> ReadUInt32(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<uint[]> ReadUInt32(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult<ulong> ReadUInt64(string address)
        {
            throw new NotImplementedException();
        }

        public BodaResult<ulong[]> ReadUInt64(string address, ushort length)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, byte[] values)
        {
            // 获取功能码和读取地址
            BodaResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, _bodaNodeModbusTcp.AddressStartWithZero, ModbusFunctionCode.WriteOneRegister);
            if (!analysis.IsSuccess) return BodaResult.CreateFailedResult<bool>(analysis);

            var wirteResult = _bodaNodeModbusTcp.PreSetMultiByteArray(analysis.Content.Address, values);
            return wirteResult;
        }

        public BodaResult Write(string address, short value)
        {
            // 获取功能码和读取地址
            BodaResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, _bodaNodeModbusTcp.AddressStartWithZero, ModbusFunctionCode.WriteOneRegister);
            if (!analysis.IsSuccess) return BodaResult.CreateFailedResult<bool>(analysis);

            var wirteResult = _bodaNodeModbusTcp.PreSetMultiReg(analysis.Content.Address, new short[] { value });
            return wirteResult;
        }

        public BodaResult Write(string address, short[] values)
        {
            // 获取功能码和读取地址
            BodaResult<ModbusAddress> analysis = ModbusInfo.AnalysisAddress(address, _bodaNodeModbusTcp.AddressStartWithZero, ModbusFunctionCode.WriteOneRegister);
            if (!analysis.IsSuccess) return BodaResult.CreateFailedResult<bool>(analysis);

            var wirteResult = _bodaNodeModbusTcp.PreSetMultiReg(analysis.Content.Address, values);
            return wirteResult;
        }

        public BodaResult Write(string address, int value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, int[] values)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, long value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, long[] values)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, float value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, float[] values)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, double value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, double[] values)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, string value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, string value, int length)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, bool value)
        {
            throw new NotImplementedException();
        }

        public BodaResult Write(string address, bool[] value)
        {
            throw new NotImplementedException();
        }

        public BodaResult WriteCustomer<T>(string address, T value) where T : IDataTransfer, new()
        {
            throw new NotImplementedException();
        }
    }
}